package instrumentation;


import java.util.*;


import util.GAConfig;
import GA.Chromosome;
import instrumentation.CoverageBranchTarget;

public class TrackerCoverage {

	private static TrackerCoverage tracker;
	// Branch Coverage
	public int[] branches= new int[GAConfig.MAX_BR];
	public int[] branchesFeasible= new int[GAConfig.MAX_BR];
	public  Map<Integer,Chromosome> branchCoveredByIndividual = new HashMap<Integer, Chromosome>() ;
	public  Map<Integer,Chromosome> branchNotCoveredByIndividual = new HashMap<Integer, Chromosome>() ;
	public  Map<Integer,Integer> tempBranchNotCoveredByIndividual = new HashMap<Integer, Integer>() ;

	

    
	private double distance ;
	private  CoverageBranchTarget condTarget ;


	private  Map<Integer,CoverageBranchTarget> trackers = new LinkedHashMap<Integer,CoverageBranchTarget>();

	public Map<Integer,CoverageBranchTarget> getTrackers(){
		return tracker.trackers;
	}
	// Delete a branch after is getting the short test case in the hill climbing to see if the the new test
	// case still hit the target branch.
	public void removeBranch(int branchId){
		tracker.trackers.remove(branchId);
		branchNotCoveredByIndividual.remove(branchId);
	}
	public void InitialTempBranchNotCovered(){
		tempBranchNotCoveredByIndividual = new HashMap<Integer, Integer>() ;
	}

	public void setTrackerToNull(){
		tracker=null;
	}
	
    public static TrackerCoverage getTracker() {
		if(tracker == null){
			tracker = new TrackerCoverage();
			tracker.trackers = new LinkedHashMap<Integer,CoverageBranchTarget>();

			}

		return tracker;
	}

	public  TrackerCoverage() {
		reset();
	}

	public void reset() {
		branches= new int[GAConfig.MAX_BR];
		branchesFeasible= new int[GAConfig.MAX_BR];
		condTarget=null;
	}
	
	public  void branchHit(int branchId) {
		if(branchId>=1  && branchId<=8)
			System.out.print("");
		branchesFeasible[branchId]=1;
		if(!tracker.trackers.containsKey(branchId)){
			condTarget = new CoverageBranchTarget(branchId);
			tracker.trackers.put(branchId,condTarget);
			branchNotCoveredByIndividual.put(branchId, null);
			tempBranchNotCoveredByIndividual.put(branchId,branchId);
		}


	}
	public void branchCovered(int branchId) {
//		if(branchId>=48  && branchId<=58)
//			System.out.print(" \n***"+branchId);
		if(trackers.containsKey(branchId)){
			branches[branchId]++;
			CoverageBranchTarget tempCondTarget=(CoverageBranchTarget)tracker.trackers.get(branchId);
			if(tempCondTarget.getBranchId()==branchId && tempCondTarget.getQuality()!=Float.NEGATIVE_INFINITY)
				tempCondTarget.setDistance(-1);
			branchNotCoveredByIndividual.remove(branchId);
			tempBranchNotCoveredByIndividual.remove(branchId);
		}
	}
	public  int getConditionTargetId(int branchId) {
		if(trackers.containsKey(branchId)){
			 condTarget=(CoverageBranchTarget)tracker.trackers.get(branchId);
			if(condTarget.getBranchId()==branchId)
				return branchId;
		}
		return -1;
	}
	
	//null==null=> 1(v1=0; v2=0)+1=>1; quality=0.5
	public void calculateConditionTargetDistance(double v1, double v2) {
		distance=(Math.abs(v1 - v2))+1;
		if(condTarget.getQuality()>=0)
			condTarget.setDistance(distance);
		if(distance<0)
			System.out.print(" ");

	}

	public int getTotalCoveredBranch() {
		int CoveredBR=0;
		List<Integer> keys = new ArrayList<Integer>( tracker.trackers.keySet());   
		for( int i=0; i<keys.size();i++){			
			CoverageBranchTarget condTarget=(CoverageBranchTarget)tracker.trackers.get(keys.get(i));
			if(condTarget.getQuality()==Float.NEGATIVE_INFINITY)
				CoveredBR++;
		}
		
		return CoveredBR;	
	}

	public float calculateFitness(Chromosome test) {
		float totalCoverageBranch=0.f;
		float branchDistance=0;
		for (int branchId = 0; branchId < branches.length; branchId++) {
			if (branches[branchId] > 0) {
				totalCoverageBranch++;		
				if(!branchCoveredByIndividual.containsKey(branchId)){
					branchCoveredByIndividual.put(branchId, test.clone());//)[branchId]=test.clone();
					branchNotCoveredByIndividual.remove(branchId);
				}
				
			}
			else{
				condTarget=(CoverageBranchTarget)tracker.trackers.get(branchId);
				if(condTarget!=null)
				if(condTarget.getQuality()!=Float.NEGATIVE_INFINITY&&condTarget.getQuality()!=Float.POSITIVE_INFINITY )
					branchDistance+=condTarget.getQuality();
			}

		}
		float fitness=totalCoverageBranch+(0.5f * (1 / (1.0f + test.getSize())));
		test.setFitness(fitness);
		test.setBranchDistance(branchDistance);
		
		return totalCoverageBranch;
		
	}	

	public float calculateBranchDistance(Chromosome test) {	
		
		return 0;
	}


	public String displayCondition(){
		List<Integer> keys = new ArrayList<Integer>( tracker.trackers.keySet());  
		StringBuilder branchs =new StringBuilder();
		for( int i=0; i<keys.size();i++){		
			String predicate;
	//		System.out.print("br=" + i);
			CoverageBranchTarget condTarget=(CoverageBranchTarget)tracker.trackers.get(keys.get(i));
			predicate =  condTarget.toString() + "\n";
			branchs.append(predicate.toString());
		}
		return branchs.toString();
	}
	  public static final String lineSep = System.getProperty("line.separator");
	@Override
	public String toString() {
		int CoveredBR=0;
		int unCoveredBR=0,idx=0;

		StringBuilder branchs =new StringBuilder();
		 int [] BRCovered = new int[tracker.trackers.size()];
		 int [] BRUnCovered = new int[tracker.trackers.size()];
		List<Integer> keys = new ArrayList<Integer>( tracker.trackers.keySet());   
		for( int i=0; i<keys.size();i++){			
			CoverageBranchTarget condTarget=(CoverageBranchTarget)tracker.trackers.get(keys.get(i));
			if(condTarget.getQuality()==Float.NEGATIVE_INFINITY){
				CoveredBR++;
				BRCovered[idx++]=keys.get(i);
			}
			else{
				BRUnCovered[unCoveredBR]=keys.get(i);
				unCoveredBR++;
			}

		}
		 branchs.append("Total Branches  ( " + keys.size()  +" ):");
		 branchs.append(lineSep);
		 branchs.append("BR Covered SUMMARY ( " + CoveredBR  +" ):");
		 branchs.append(lineSep);
		 if (!GAConfig.Silent) {
			Arrays.sort(BRCovered);
			for (int i = 0; i < BRCovered.length; i++)
				if (BRCovered[i] != 0)
					branchs.append("B" + BRCovered[i] + " ");
			branchs.append(lineSep);
		}
		branchs.append("BR unCovered SUMMARY ( " + unCoveredBR  +" ): ");
		branchs.append(lineSep);
//		 if (!GAConfig.Silent) {
			Arrays.sort(BRUnCovered);
			for (int i = 0; i < BRUnCovered.length; i++)
				if (BRUnCovered[i] != 0){
					branchs.append("B" + BRUnCovered[i] + " ");
//					if(  branchNotCoveredByIndividual.get(BRUnCovered[i] )!=null)
//						branchs.append(" testCase: "  + branchNotCoveredByIndividual.get(BRUnCovered[i]).toString()+"\n");
				}
			branchs.append(lineSep);
//		}

		return branchs.toString(); 
	}
	


	
}